import os
from http import HTTPStatus
from dashscope import Application
from fastapi import APIRouter, Body, Request, Depends
from configs.other_config import CHAT_WITH_OWN_PET_NO_OCCUPATION_APPID, CHAT_WITH_OWN_PET_WITH_OCCUPATION_APPID, DASHSCOPE_API_KEY, ALGORITHM
from configs.kb_config import GO_SERVICE_SECRET_KEY, ENVIRONMENT
from configs.logging_config import configure_logging
from server.db.models.message_model import MarsXChatWithOtherPetSession
from server.db.models.pet_kb_model import PetKnowledgeBase
from server.db.models.memory_model import Memory
from server.bailian.memory_client import client as memory_client
from server.bailian.own_other_token import verify_owner_authorization
from typing import Optional, Union, Generator
from dashscope.app.application import ApplicationResponse
from server.utils import create_chat_response, BaseResponse, decode_verify_token
import json
from loguru import logger
from sse_starlette.sse import EventSourceResponse
from server.db.session import get_db
from sqlalchemy.orm import Session
from sqlalchemy import and_
from datetime import datetime, timedelta
import pytz
import asyncio
from configs.other_config import STREAM_RETURN_INTERVAL

configure_logging()
router = APIRouter()

@router.post("/bailian/v1/chat/chat_with_other_pet")
async def chat_with_other_pet_v1(uid: str = Body(..., embed=True, description="用户ID"), 
                            pet_id: str = Body(..., embed=True, description="宠物ID，也就是他人宠物的ID，也就是他人的用户ID"),
                            conversation_id: Optional[str] = Body(None, embed=True, description="会话ID"),
                            stream: bool = Body(True, embed=True, description="是否流式输出"),
                            nickname: str = Body(..., embed=True, description="昵称"),
                            character: str = Body(..., embed=True, description="性格"),
                            query: str = Body(..., embed=True, description="用户输入"),
                            occupation: str = Body(None, embed=True, description="职业"),
                            use_knowledge_base: bool = Body(False, embed=True, description="是否使用专属知识库模式"),
                            request: Request = None,
                            db: Session = Depends(get_db)):
    
    # 解码token
    try:
        token = decode_verify_token(request, GO_SERVICE_SECRET_KEY, ALGORITHM)
    except Exception as e:
        return BaseResponse(code=401, msg="Token is invalid", data={"error": str(e.detail.get('msg'))})
    
    beijing_timezone = pytz.timezone("Asia/Shanghai")
    beijing_time = datetime.now(beijing_timezone)
    beijing_time_str = beijing_time.strftime("%Y-%m-%d %H:%M:%S")
    # 星期几
    weekday = beijing_time.weekday()
    weekday_str = ["一", "二", "三", "四", "五", "六", "日"][weekday]
    
    # 知识库模式检查（知识库模式不使用记忆体）
    pipeline_ids = None
    memory_id = None
    
    if use_knowledge_base:
        # 验证用户是否有权限访问该宠物的知识库
        verification_result = verify_owner_authorization(uid=int(pet_id), pet_id=int(uid))
        
        if not verification_result["success"]:
            logger.warning(f"用户 {uid} 请求与他人宠物 {pet_id} 对话（知识库模式），授权验证请求失败: {verification_result['message']}")
            return BaseResponse(
                code=500,
                msg=f"授权验证失败: {verification_result['message']}",
                data={}
            )
        
        if not verification_result["has_authorization"]:
            logger.warning(f"用户 {uid} 请求与他人宠物 {pet_id} 对话（知识库模式），但该宠物未开启授权")
            return BaseResponse(
                code=403,
                msg="该宠物未开启知识库访问授权",
                data={"has_authorization": False}
            )
        
        if not verification_result["key_valid"]:
            logger.warning(f"用户 {uid} 请求与他人宠物 {pet_id} 对话（知识库模式），但授权验证未通过")
            return BaseResponse(
                code=403,
                msg="您没有权限访问该宠物的知识库",
                data={"key_valid": False}
            )
        
        logger.info(f"用户 {uid} 授权验证通过，可以访问他人宠物 {pet_id} 的知识库")
        
        # 获取宠物主人（pet_id）的知识库
        pet_kb = db.query(PetKnowledgeBase).filter(
            PetKnowledgeBase.user_id == pet_id
        ).first()
        
        if not pet_kb:
            logger.warning(f"用户 {uid} 请求与他人宠物 {pet_id} 对话（知识库模式），但该宠物未创建知识库")
            return BaseResponse(
                code=404,
                msg="该宠物未创建专属知识库，请使用非知识库模式或等待宠物主人创建知识库",
                data={}
            )
        
        if pet_kb.document_count == 0:
            logger.warning(f"他人宠物 {pet_id} 的知识库为空")
            return BaseResponse(
                code=400,
                msg="该宠物的知识库中没有文档",
                data={}
            )
        
        pipeline_ids = [pet_kb.knowledge_base_id]
        logger.info(f"与他人宠物对话（知识库模式） 用户ID: {uid} | 宠物ID: {pet_id} | 知识库ID: {pet_kb.knowledge_base_id}")
    else:
        # 记忆体模式：获取宠物主人的记忆体ID（如果有的话）
        memory_object = db.query(Memory).filter(Memory.user_id == pet_id, Memory.memory_id != "").first()
        if memory_object is not None:
            memory_id = memory_object.memory_id
            logger.info(f"与他人宠物对话（记忆体模式，有记忆体） 用户ID: {uid} | 宠物ID: {pet_id} | 记忆体ID: {memory_id}")
        else:
            # 即使没有记忆体也允许对话，只是对话内容不会包含个性化的训练数据
            memory_id = None
            logger.info(f"与他人宠物对话（记忆体模式，无记忆体） 用户ID: {uid} | 宠物ID: {pet_id} | 提示：该宠物暂未训练，对话将不包含个性化内容")
    
    """
    与他人宠物对话
    """
    if not occupation:
        biz_params = {
            "user_prompt_params": {
                "nickname": nickname,
                "character": character,
                "time": beijing_time_str + " 星期" + weekday_str
            }
        }
        app_id = CHAT_WITH_OWN_PET_NO_OCCUPATION_APPID
    else:
        biz_params = {
            "user_prompt_params": {
                "nickname": nickname,
                "character": character,
                "occupation": occupation,
                "time": beijing_time_str + " 星期" + weekday_str
            }
        }
        app_id = CHAT_WITH_OWN_PET_WITH_OCCUPATION_APPID
    
    # 获取该用户与该宠物的最新会话（按创建时间倒序）
    session_object = db.query(MarsXChatWithOtherPetSession).filter(
        and_(MarsXChatWithOtherPetSession.user_id == uid, 
             MarsXChatWithOtherPetSession.conversation_id != "")
        ).order_by(MarsXChatWithOtherPetSession.created_time.desc()).first()
    
    # 获取会话的首次创建时间（需要查询同会话ID的最早记录）
    first_created_time = None
    if session_object:
        first_session = db.query(MarsXChatWithOtherPetSession).filter(
            MarsXChatWithOtherPetSession.conversation_id == session_object.conversation_id
        ).order_by(MarsXChatWithOtherPetSession.created_time.asc()).first()
        first_created_time = first_session.created_time if first_session else None 
    # 双重时间校验
    valid_session = False
    if session_object and first_created_time:
        last_active_expired = datetime.now() - session_object.created_time > timedelta(minutes=10)
        first_create_expired = datetime.now() - first_created_time > timedelta(minutes=50)
        
        if not last_active_expired and not first_create_expired:
            valid_session = True
            conversation_id = session_object.conversation_id
        else:
            # 仅重置会话ID（保留历史记录）
            # 生成新会话ID（由阿里云API返回）
            conversation_id = None  
            
            # 可选：标记旧会话为已过期
            db.query(MarsXChatWithOtherPetSession).filter(
                MarsXChatWithOtherPetSession.conversation_id == session_object.conversation_id
            ).update({"is_expired": True})
            db.commit()
    else:
        conversation_id = None

    # 构建API调用参数
    call_params = {
        "api_key": os.getenv("DASHSCOPE_API_KEY", DASHSCOPE_API_KEY),
        "app_id": app_id,
        "prompt": query,
        "stream": True,
        "incremental_output": True,
        "biz_params": biz_params
    }
    
    # 知识库模式：使用知识库，不使用记忆体
    if use_knowledge_base and pipeline_ids:
        call_params["rag_options"] = {"pipeline_ids": pipeline_ids}
        logger.info(f"知识库模式调用 用户ID: {uid} | 宠物ID: {pet_id} | 知识库ID: {pipeline_ids}")
    else:
        # 记忆体模式：使用记忆体（如果有），不使用知识库
        if memory_id:
            call_params["memory_id"] = memory_id
            logger.info(f"记忆体模式调用（有记忆体） 用户ID: {uid} | 宠物ID: {pet_id} | 记忆体ID: {memory_id}")
        else:
            logger.info(f"记忆体模式调用（无记忆体） 用户ID: {uid} | 宠物ID: {pet_id} | 将使用默认对话模式")
    
    # 只有当有有效会话时才传递session_id
    if valid_session:
        call_params["session_id"] = conversation_id

    responses = Application.call(**call_params)
    async def event_generator(responses: Union[ApplicationResponse, Generator[ApplicationResponse, None, None]]):
        full_answer = ""
        session_id = None
        request_id = None
        code = None
        for response in responses:
            # response.output.session_id # 会话ID
            if response.status_code != HTTPStatus.OK:
                request_id = response.request_id
                code = response.status_code
                session_id = ""
                session_object = MarsXChatWithOtherPetSession(
                    user_id=uid,
                    pet_id=pet_id,
                    conversation_id=session_id,
                    request_id=request_id,
                    user_input=query
                )
                try:
                    db.add(session_object)
                    db.commit()
                except Exception as e:
                    db.rollback()
                    logger.error(f"与他人宠物对话时，创建会话时数据库操作失败 用户ID: {uid} | 他人用户ID: {pet_id} | 用户输入: {query} | 错误信息: {e}")
                logger.error(f"错误信息: {response.code} | {response.message} 请求ID: {request_id} 用户ID: {uid} 他人用户ID: {pet_id} 会话ID: {session_id} 用户输入: {query}")
                yield create_chat_response(
                    response_text=None,
                    instruction="-1",
                    request_id=request_id,
                    finish=True,
                    code=code,
                    data_content={
                        "error_type": response.code,
                        "error_message": response.message
                    }
                )
                return
            else:
                if stream:
                    answer = response.output.text
                    full_answer += answer
                    request_id = response.request_id
                    code = response.status_code

                    # 新增：返回时间
                    beijing_timezone = pytz.timezone("Asia/Shanghai")
                    current_time = datetime.now(beijing_timezone).strftime("%Y-%m-%d %H:%M:%S")

                    await asyncio.sleep(STREAM_RETURN_INTERVAL)
                    yield create_chat_response(
                        response_text=answer,
                        instruction="-1",
                        request_id=request_id,
                        finish=False,
                        code=code,
                        data_content={
                            "time": current_time
                        }
                    )
            session_id = response.output.session_id
        session_object = MarsXChatWithOtherPetSession(
            user_id=uid,
            pet_id=pet_id,
            conversation_id=session_id,
            request_id=request_id,
            user_input=query,
            assistant_answer=full_answer
        )
        try:
            db.add(session_object)
            db.commit()
        except Exception as e:
            db.rollback()
            logger.error(f"与他人宠物对话时，创建会话时数据库操作失败 用户ID: {uid} | 他人用户ID: {pet_id} | 用户输入: {query} | 错误信息: {e}")
        logger.info(f"用户{uid}的会话ID为{session_id} | 他人用户ID: {pet_id} | 用户输入为：{query} | 智能体回答为：{full_answer}")
        await asyncio.sleep(STREAM_RETURN_INTERVAL)
        yield create_chat_response(
            response_text=full_answer,
            instruction="-1",
            request_id=request_id,
            finish=True,
            code=code,
            data_content={
                "time": current_time
            }
        )
    return EventSourceResponse(event_generator(responses))